package com.toppitch.site.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.toppitch.site.config.AppConfig;
import com.toppitch.site.data.Comment;
import com.toppitch.site.data.JsonData;
import com.toppitch.site.data.Pitch;
import com.toppitch.site.data.Student;
import com.toppitch.site.data.User;
import com.toppitch.site.db.DBManager;
import com.toppitch.site.db.IGetFromResultSet;

@Controller
@RequestMapping("/pitch")
public class PitchController extends BaseController {

	@Autowired
	private DBManager dbmanager;

	@Autowired
	private AppConfig appConfig = null;

	@PostConstruct
	public void init() {
		File f = new File(appConfig.getRoot() + appConfig.getMap().get("THESIS_PATH"));
		if (!f.exists()) {
			f.mkdirs();
		}
		f = new File(appConfig.getRoot() + appConfig.getMap().get("VARIANT_VIEW_PATH"));
		if (!f.exists()) {
			f.mkdirs();
		}
		f = new File(appConfig.getRoot() + appConfig.getMap().get("COMMENT_PATH"));
		if (!f.exists()) {
			f.mkdirs();
		}
	}

	@RequestMapping("")
	public String getPitch(@RequestParam("pitchId") String pitchId, HttpSession session, ModelMap modelMap) {
		setupNYTNews(modelMap);
		Object st = session.getAttribute("STUDENT");
		if (st == null) {
			st = session.getAttribute("HF");
		}
		if (st != null && st instanceof User) {
			final User user = (User) st;
			modelMap.addAttribute("user", st);

			// pitch
			Pitch pitch = new Pitch();
			dbmanager.queryFirst(pitch, "select * from pitch where pitchId=?", pitchId);

			modelMap.addAttribute("pitch", pitch);

			// thesis
			String thesis = "";
			StringBuilder sb = new StringBuilder();
			byte[] bs = new byte[1024];
			int len = 0;
			FileInputStream fis = null;
			try {
				fis = new FileInputStream(new File(appConfig.getRoot() + appConfig.getMap().get("THESIS_PATH") + pitch.getThesisId()));
				while ((len = fis.read(bs)) > 0) {
					sb.append(new String(bs, 0, len));
				}
				thesis = sb.toString();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (fis != null) {
					try {
						fis.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					fis = null;
				}
			}
			modelMap.addAttribute("thesis", thesis);

			// variant view
			String variantView = "";
			sb.setLength(0);
			bs = new byte[1024];
			len = 0;
			try {
				fis = new FileInputStream(new File(appConfig.getRoot() + appConfig.getMap().get("VARIANT_VIEW_PATH") + pitch.getVariantViewId()));
				while ((len = fis.read(bs)) > 0) {
					sb.append(new String(bs, 0, len));
				}
				variantView = sb.toString();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (fis != null) {
					try {
						fis.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					fis = null;
				}
			}
			modelMap.addAttribute("variantView", variantView);

			// author
			Student student = new Student();
			dbmanager.queryFirst(student, "select * from student where lower(email)=?", pitch.getAuthorEmail().toLowerCase());
			modelMap.addAttribute("author", student);

			// comments
			final List<Comment> comments = new ArrayList<Comment>();
			dbmanager.doQuery(new IGetFromResultSet() {
				public void getFromResultSet(ResultSet rs) throws SQLException {
					while (rs.next()) {
						Comment comment = new Comment();
						comment.getFromResultSet(rs);
						// text
						StringBuilder sb = new StringBuilder();
						byte[] bs = new byte[1024];
						int len = 0;
						FileInputStream fis = null;
						try {
							fis = new FileInputStream(new File(appConfig.getRoot() + appConfig.getMap().get("COMMENT_PATH") + comment.getCommentId()));
							while ((len = fis.read(bs)) > 0) {
								sb.append(new String(bs, 0, len));
							}
							comment.setCommentText(sb.toString());
						} catch (FileNotFoundException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						} finally {
							if (fis != null) {
								try {
									fis.close();
								} catch (IOException e) {
									e.printStackTrace();
								}
								fis = null;
							}
						}
						if (comment.isStudentAuthor()) {
							// student profile available
							Student student = new Student();
							dbmanager.queryFirst(student, "select * from student where lower(email)=?", comment.getAuthorEmail().toLowerCase());
							if (user.isStudent()) {
								comment.setAuthorAvailable(student.isAvailableToPublic());
							} else {
								comment.setAuthorAvailable(student.isAvailableToHf());
							}
						} else {
							comment.setAuthorAvailable(false);
						}
						comments.add(comment);
					}
				}

			}, "select * from comment where pitchId=?", pitchId);
			modelMap.addAttribute("comments", comments);

			return "pitch";
		}
		return "login";
	}

	@RequestMapping("/addComment")
	public String addComment(//
			@RequestParam("commentText") String commentText,//
			@RequestParam("pitchId") String pitchId,//
			HttpSession session, ModelMap modelMap) {
		JsonData json = new JsonData();
		modelMap.addAttribute("jsonData", json);
		Object st = session.getAttribute("STUDENT");
		if (st == null) {
			st = session.getAttribute("HF");
		}
		if (st != null && st instanceof User) {
			Comment comment = new Comment();
			String commentId = "" + System.currentTimeMillis();
			File f = new File(appConfig.getRoot() + appConfig.getMap().get("COMMENT_PATH") + commentId);
			OutputStream os = null;
			try {
				os = new FileOutputStream(f);
				os.write(change(commentText).getBytes());
				os.flush();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (os != null) {
					try {
						os.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					os = null;
				}
			}
			comment.setCommentId(commentId);
			comment.setPitchId(pitchId);
			comment.setAuthorEmail(((User) st).getEmail());
			comment.setPostTime(System.currentTimeMillis());
			comment.setAuthorHF(((User) st).isStudent() ? "false" : "true");
			comment.setAuthorName(((User) st).getFullName());
			comment.setAuthorPhotoId(((User) st).getPhotoId());
			json.setSucceed(dbmanager.execute(comment.toInsertString()));
			if (json.isSucceed()) {
				setCommentCount(pitchId);
			} else {
				json.setErrorMessage("Failed to update database");
			}
		} else {
			json.setErrorMessage("Please login as a student");
		}
		return "json";
	}

	@RequestMapping("/deletePitch")
	public String deletePitch(@RequestParam("pitchId") String pitchId, HttpSession session, ModelMap modelMap) {
		Object st = session.getAttribute("STUDENT");
		if (st != null && st instanceof Student) {
			Student student = (Student) st;
			String email = student.getEmail();
			dbmanager.execute("delete from pitch where pitchId='" + pitchId + "' and lower(authorEmail)='" + email.toLowerCase() + "'");
			setPitchCount(student.getEmail(), student);
			setModelCount(student.getEmail(), student);
		}
		JsonData json = new JsonData();
		json.setSucceed(true);
		modelMap.addAttribute("jsonData", json);
		return "json";
	}

	@RequestMapping("/edit")
	public String editPitch(//
			@RequestParam("companyTicker") String companyTicker,//
			@RequestParam("companyName") String companyName,//
			@RequestParam("currentPrice") String currentPrice,//
			@RequestParam("targetPrice") String targetPrice,//
			@RequestParam("assetClass") String assetClass,//
			@RequestParam("geography") String geography,//
			@RequestParam("recommendation") String recommendation,//
			@RequestParam("country") String country,//
			@RequestParam("expectedTimeframe") String expectedTimeframe,//
			@RequestParam("situation") String situation,//
			@RequestParam("sector") String sector,//
			@RequestParam("ideaAvailability") String ideaAvailability,//
			@RequestParam("thesis") String thesis,//
			@RequestParam("variantView") String variantView,//
			@RequestParam("modelId") String modelId,//
			@RequestParam("modelType") String modelType,//
			@RequestParam("modelFileName") String modelFileName,//
			@RequestParam("description") String description,//
			HttpSession session, ModelMap modelMap) {
		JsonData json = new JsonData();
		modelMap.addAttribute("jsonData", json);
		Object st = session.getAttribute("STUDENT");
		if (st != null && st instanceof Student) {
			Student student = (Student) st;
			Pitch pitch = new Pitch();
			pitch.setCompanyTicker(companyTicker);
			pitch.setCompanyName(companyName);
			pitch.setCurrentPrice(currentPrice);
			pitch.setTargetPrice(targetPrice);
			pitch.setAssetClass(assetClass);
			pitch.setGeography(geography);
			pitch.setRecommendation(recommendation);
			pitch.setCountry(country);
			pitch.setExpectedTimeframe(expectedTimeframe);
			pitch.setSituation(situation);
			pitch.setSector(sector);
			pitch.setIdeaAvailability(ideaAvailability);
			String thesisId = "" + System.currentTimeMillis();
			File f = new File(appConfig.getRoot() + appConfig.getMap().get("THESIS_PATH") + thesisId);
			OutputStream os = null;
			try {
				os = new FileOutputStream(f);
				os.write(change(thesis).getBytes());
				os.flush();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (os != null) {
					try {
						os.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					os = null;
				}
			}
			String variantViewId = "" + System.currentTimeMillis();
			f = new File(appConfig.getRoot() + appConfig.getMap().get("VARIANT_VIEW_PATH") + variantViewId);
			try {
				os = new FileOutputStream(f);
				os.write(change(variantView).getBytes());
				os.flush();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (os != null) {
					try {
						os.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			pitch.setThesisId(thesisId);
			pitch.setVariantViewId(variantViewId);
			pitch.setModelId(modelId);
			pitch.setModelType(modelType);
			pitch.setModelFileName(modelFileName);
			pitch.setDescription(description);
			pitch.setAuthorEmail(student.getEmail());
			pitch.setAuthorFullName(student.getFirstName() + " " + student.getLastName());
			pitch.setPosttime(System.currentTimeMillis());
			pitch.setCommentCount(0);
			pitch.setPitchId("" + System.currentTimeMillis());
			json.setSucceed(dbmanager.execute(pitch.toInsertString()));
			if (json.isSucceed()) {
				setPitchCount(student.getEmail(), student);
				setModelCount(student.getEmail(), student);
			} else {
				json.setErrorMessage("Failed to update database");
			}
		}
		return "json";
	}

	private void setModelCount(final String email, final Student student) {
		dbmanager.doQuery(new IGetFromResultSet() {
			public void getFromResultSet(ResultSet rs) throws SQLException {
				int c = 0;
				if (rs.next()) {
					c = rs.getInt("c");
				}
				dbmanager.execute("update student set modelCount=" + c + " where lower(email)='" + email.toLowerCase() + "'");
				student.setModelCount(c);
			}
		}, "select count(modelId) as c from pitch where modelId!='' and lower(authorEmail)=?", email.toLowerCase());
	}

	private void setPitchCount(final String email, final Student student) {
		dbmanager.doQuery(new IGetFromResultSet() {
			public void getFromResultSet(ResultSet rs) throws SQLException {
				int c = 0;
				if (rs.next()) {
					c = rs.getInt("c");
				}
				dbmanager.execute("update student set pitchCount=" + c + " where lower(email)='" + email.toLowerCase() + "'");
				student.setPitchCount(c);
			}
		}, "select count(pitchId) as c from pitch where lower(authorEmail)=?", email.toLowerCase());
	}

	private void setCommentCount(final String pitchId) {
		dbmanager.doQuery(new IGetFromResultSet() {
			public void getFromResultSet(ResultSet rs) throws SQLException {
				int c = 0;
				if (rs.next()) {
					c = rs.getInt("c");
				}
				dbmanager.execute("update pitch set commentCount=" + c + " where pitchId='" + pitchId + "'");
			}
		}, "select count(commentId) as c from comment where pitchId=?", pitchId);
	}

	private String change(String in) {
		String str = in.replace("&", "&amp;").replace("\"", "&quot;").replace("<", "&lt;").replace(">", "&gt;");
		str = "<p>" + str.replaceAll("\\r?\\n", "</p><p>");
		if (!str.endsWith("</p>")) {
			str += "</p>";
		}
		return str;
	}
}
